﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using School.Entities;
using School.Common;

namespace School.Accounting
{
    public static class LatePayment
    {
        private static SchoolEntities db = new SchoolEntities();

        public static IEnumerable<ACC_Student_Balance> GetBalance(long Campus = 0, long Certificate = 0, long Stage = 0, long Grade = 0, int Class = 0, long Student = 0)
        {
            long CurrentYear = Structure.GetCurrentEductionalYear().Select(x => x.Id).First();

            var rows = from x in db.ACC_Student_Balance where x.Educational_Year == CurrentYear && x.Value > 0 select x;

            if (Campus != 0)
                rows = rows.Where(x => x.TE_Student.Campus_Id == Campus);

            if (Certificate != 0)
                rows = rows.Where(x => x.TE_Student.Certificate_Id == Certificate);

            if (Stage != 0)
                rows = rows.Where(x => x.TE_Student.Stage_Id == Stage);

            if (Grade != 0)
                rows = rows.Where(x => x.TE_Student.Grade_ID == Grade);

            if (Class != 0)
                rows = rows.Where(x => db.TE_Class_Student.Where(y => y.Student_Id == x.Student_Id).Select(y => y.Class_Id).Contains(Class) == true);

            if (Student != 0)
                rows = rows.Where(x => x.Student_Id == Student);

            return rows;
        }

        public static List<IncompleteVoucherObject> GetVouchers(long Campus = 0, long Certificate = 0, long Stage = 0, long Grade = 0, int Class = 0, long Student = 0, List<long> expenses = null)
        {
            long CurrentYear = Structure.GetCurrentEductionalYear().Select(x => x.Id).First();

            List<IncompleteVoucherObject> IncompleteVouchers = new List<IncompleteVoucherObject>();

            var rows = from x in db.ACC_Voucher where x.Current_Educational_Year == CurrentYear && x.Is_Active == true && x.Payment_Order_Number != 0 select x;

            if (Campus != 0)
                rows = rows.Where(x => x.TE_Student.Campus_Id == Campus);

            if (Certificate != 0)
                rows = rows.Where(x => x.TE_Student.Certificate_Id == Certificate);

            if (Stage != 0)
                rows = rows.Where(x => x.TE_Student.Stage_Id == Stage);

            if (Grade != 0)
                rows = rows.Where(x => x.TE_Student.Grade_ID == Grade);

            if (Class != 0)
                rows = rows.Where(x => db.TE_Class_Student.Where(y => y.Student_Id == x.Student_Id).Select(y => y.Class_Id).Contains(Class) == true);

            if (Student != 0)
                rows = rows.Where(x => x.Student_Id == Student);

            if (expenses != null)
                if (expenses.Count() > 0)
                {
                    rows = rows.Where(x => expenses.Contains(x.Expense_Id));
                }

            var PaymentOrderNumbers = rows.Select(x => x.Payment_Order_Number).Distinct();

            foreach (long p in PaymentOrderNumbers)
            {
                var payments = Voucher.GetPaymentOrdersByNumber(p);

                PaymentOrderObject payment = new PaymentOrderObject();

                if (payments.Count() > 0)
                    payment = payments.First();

                var vs = rows.Where(x => x.Payment_Order_Number == p);

                if (vs.Count() == 1)
                {
                    var v = vs.First();

                    if (payment.Value > v.Value)
                        IncompleteVouchers.Add(new IncompleteVoucherObject() { PaymentOrderNumber = v.Payment_Order_Number, StudentNumber = !string.IsNullOrEmpty(v.TE_Student.RegistrationNumber.ToString()) ? long.Parse(v.TE_Student.RegistrationNumber.ToString()) : 0, ExpenseName = v.ACC_Expense.Name, OriginalValue = payment.Value, PaidValue = v.Value, RemainingValue = payment.Value - v.Value, StudentName = v.TE_Student.Ar_FirstName + " " + v.TE_Student.Ar_SecondName + " " + v.TE_Student.Ar_ThirdNmae + " " + v.TE_Student.Ar_FourthName });
                }
                else if (vs.Count() > 1)
                {
                    List<ACC_Voucher> temp = new List<ACC_Voucher>();
                    decimal value = 0;

                    ACC_Voucher v = new ACC_Voucher();

                    foreach (var vt in vs)
                    {
                        value += vt.Value;
                        temp.Add(vt);
                        v = vt;
                    }

                    if (payment.Value > value)
                        IncompleteVouchers.Add(new IncompleteVoucherObject() { PaymentOrderNumber = v.Payment_Order_Number, StudentNumber = long.Parse(v.TE_Student.RegistrationNumber.ToString()), ExpenseName = v.ACC_Expense.Name, OriginalValue = payment.Value, PaidValue = value, RemainingValue = payment.Value - value, StudentName = v.TE_Student.Ar_FirstName + " " + v.TE_Student.Ar_SecondName + " " + v.TE_Student.Ar_ThirdNmae + " " + v.TE_Student.Ar_FourthName }); ;
                }
            }

            return IncompleteVouchers;
        }

        public static IEnumerable<PaymentObject> GetPayments(long Campus = 0, long Certificate = 0, long Stage = 0, long Grade = 0, int Class = 0, long Student = 0, List<long> expenses = null)
        {
            var students = from x in db.TE_Student select x;

            if (Campus != 0)
                students = students.Where(x => x.Campus_Id == Campus);

            if (Certificate != 0)
                students = students.Where(x => x.Certificate_Id == Certificate);

            if (Stage != 0)
                students = students.Where(x => x.Stage_Id == Stage);

            if (Grade != 0)
                students = students.Where(x => x.Grade_ID == Grade);

            if (Class != 0)
                students = students.Where(x => x.TE_Class_Student.Select(y => y.Class_Id).Contains(Class));

            if (Student != 0)
                students = students.Where(x => x.Id == Student);

            List<PaymentObject> np = new List<PaymentObject>();

            foreach (var x in students)
            {
                var es = Expense.GetExpensesByStudent(x.Id).Select(xex => xex.ID);

                var payments = from xp in db.ACC_Expense_Payments where es.Contains(xp.ACC_Expense.ID) == true && xp.Due_Date <= DateTime.Now select xp;

                var currentYear = Structure.GetCurrentEductionalYear().First().Id;

                var paymentOrders = (from xv in db.ACC_Voucher_Payment_Order where es.Contains(xv.ACC_Voucher.ACC_Expense.ID) == true & xv.ACC_Voucher.Current_Educational_Year == currentYear & xv.ACC_Voucher.Student_Id == x.Id select xv.Payment_Order_Number).ToList();

                foreach (var paymentOrder in paymentOrders)
                {
                    payments = payments.Where(xp => xp.ACC_Payment_Order.Select(yp => yp.Payment_Order_Number).Contains(paymentOrder) == false);
                }

                foreach (ACC_Expense_Payments p in payments)
                {
                    np.Add(new PaymentObject() { StudentId = x.Id, PaymentId = p.Id, Date = p.Due_Date, StudentNumber = x.RegistrationNumber, ExpenseName = p.ACC_Expense.Name, Value = p.Value, StudentName = x.Ar_FirstName + " " + x.Ar_SecondName + " " + x.Ar_ThirdNmae + " " + x.Ar_FourthName });
                }
            }

            return np;
        }

        public static long PayBalance(long student, decimal paid, DateTime voucherDate)
        {
            try
            {
                var CurrentYear = Structure.GetCurrentEductionalYear().Select(x => x.Id).First();

                var ExpenseId = (from x in db.ACC_Expenses_Screens where x.SEC_Screen.Code == "500" select x.Expense_Id).First();

                var PaymentId = (from x in db.ACC_Expense_Payments where x.Expense_Id == ExpenseId select x.Id).First();

                var NewPaymentOrder = new ACC_Payment_Order() { Payment_Id = PaymentId, Value = paid, Educational_Year = CurrentYear, Date = DateTime.Now, Student_Id = student };

                var PaymentOrderNumber = PaymentOrder.AddPaymentOrder(NewPaymentOrder);

                var VoucherNumber = Voucher.AddVoucherFromPaymentOrder(new PaymentOrderObject() { Student_Id = student, NoStudent = false, Expense_Id = ExpenseId, Number = PaymentOrderNumber }, paid, voucherDate);

                var balance = db.ACC_Student_Balance.Single(x => x.Student_Id == student);

                balance.Value -= paid;
                db.SaveChanges();

                return VoucherNumber;
            }
            catch
            {
                return 0;
            }
        }

        public static long PayVoucher(long PaymentOrderNumber, decimal paid, DateTime voucherDate)
        {
            try
            {
                var p = Voucher.GetPaymentOrdersByNumber(PaymentOrderNumber).First();

                var v = Voucher.AddVoucherFromPaymentOrder(p, paid, voucherDate);

                return v;
            }
            catch
            {
                return 0;
            }
        }

        public static long PayPayment(long Payment, long Student, decimal paid, DateTime voucherDate)
        {
            try
            {
                var payment = db.ACC_Expense_Payments.Single(x => x.Id == Payment);

                var paymentOrder = PaymentOrder.AddPaymentOrder(new ACC_Payment_Order() { Payment_Id = Payment, Student_Id = Student, Value = payment.Value });

                var voucher = Voucher.AddVoucherFromPaymentOrder(new PaymentOrderObject() { Expense_Id = payment.Expense_Id, Student_Id = Student, NoStudent = false, Number = paymentOrder }, paid, voucherDate);

                return voucher;
            }
            catch
            {
                return 0;
            }
        }
    }

    public class IncompleteVoucherObject
    {
        public string ExpenseName { get; set; }
        public long StudentNumber { get; set; }
        public string StudentName { get; set; }
        public decimal OriginalValue { get; set; }
        public decimal PaidValue { get; set; }
        public decimal RemainingValue { get; set; }
        public long PaymentOrderNumber { get; set; }
    }

    public class PaymentObject
    {
        public string ExpenseName { get; set; }
        public decimal Value { get; set; }
        public string StudentName { get; set; }
        public long? StudentNumber { get; set; }
        public DateTime? Date { get; set; }
        public long StudentId { get; set; }
        public long PaymentId { get; set; }
    }
    public class StudentInfo
    {
        public long Campus { get; set; }
        public long Certificate { get; set; }
        public long Stage { get; set; }
        public long Grade { get; set; }
        public int XClass { get; set; }
        public long Student { get; set; }
        public List<long> Expenses { get; set; }
    }
}
